
#include "helpers.h"
#include "alloc_context_impl.h"

#define GET_BLOCKS_COUNT_IMPL( func_name, arr_list_type )\
    static size_t func_name( const arr_list_type * arr_list )\
    {\
        size_t      result = 0; \
        for( ; arr_list != 0; arr_list = arr_list->next ) { ++ result; } \
        return result; \
    }




GET_BLOCKS_COUNT_IMPL( list_blocks_count, ListBlock );

static size_t
alloc_bits( unsigned int i )
{
    size_t  result = 0;
    size_t  n;
    
    for( n = 0; n < QL_CHUNK_NUM_BITS; ++ n )
    {
        if( 0 != (i & 1) )
        {
            ++ result;
        }

        i = i >> 1;
    }

    return result;
}

static size_t
list_block_size( const ListBlock * b, size_t alloc_size )
{
    size_t  result = 0;
    size_t  n;

    for( n = 0; n < alloc_size; ++ n )
    {
        result += alloc_bits( b->chunks[n].free_mask );
    }

    return result;
}

static size_t
list_blocks_size( const ListBlock * b, size_t alloc_size )
{
    size_t  result = 0;
    for( ; b != 0; b = b->next )
    {
        result += list_block_size( b, alloc_size );
    }
    return result;
}

/*
 * dumps memory usage of the lists
 */
static size_t
dump_list_mem_state( AllocContext * c, FILE * fout )
{
    const ListBlock *   b = c->impl->lists.blk;
    const size_t        blk_count = list_blocks_count( b );
    const size_t        blk_size = (c->settings.list_chunks_alloc_size - 1) * sizeof(ListChunk) +
        sizeof(ListBlock);

    const size_t        total_blocks_size = blk_size * blk_count;

    fprintf(
        fout,
        "List allocator memory consumption:\n"
        "\tLists allocated:   %d\n"
        "\tMax lists/block:   %d\n"
        "\tBlocks count:      %d\n"
        "\tBlock size:        %d bytes\n"
        "\tTotal blocks size: %d bytes\n"
        "------------------------------------\n"
        ,
        list_blocks_size( b, c->settings.list_chunks_alloc_size ),
        c->settings.list_chunks_alloc_size * QL_CHUNK_NUM_BITS,
        blk_count,
        blk_size,
        total_blocks_size
        );

    return total_blocks_size;
}



GET_BLOCKS_COUNT_IMPL( ids_arrays_count, IdArr );
GET_BLOCKS_COUNT_IMPL( lit_arrays_count, LitArr );


/*
 * dumps memory usage of the identifiers
 */
static size_t
dump_ids_mem_state( AllocContext * c, FILE * fout )
{
    const IdArr *       id_arr = c->impl->ids.id_arr;
    const LitArr *      lit_arr = c->impl->ids.lit_arr;
    const SortedIdsArr * sia = &c->impl->ids.sorted_ids;

    const size_t        id_arrs_count = ids_arrays_count( id_arr );
    const size_t        id_arr_size = (c->settings.id_arr_grow_size - 1) * sizeof(Id) + sizeof(IdArr);
    const size_t        total_ids_size = id_arrs_count * id_arr_size;

    const size_t        lit_arrs_count = lit_arrays_count( lit_arr );
    const size_t        lit_arr_size = (c->settings.literals_arr_grow_size - 1) * sizeof(char) + sizeof(LitArr);
    const size_t        total_lits_size = lit_arrs_count * lit_arr_size;

    const size_t        total_sia_size = sia->allocated * sizeof(Id *);

    fprintf( fout,
        "Identifiers allocator memory consumption:\n"
        "Identifers arrays:\n"
        "\tArrays count:      %d\n"
        "\tSize of array:     %d bytes\n"
        "\tTotal size:        %d bytes\n"
        "Literals arrays:\n"
        "\tArrays count:      %d\n"
        "\tSize of array:     %d bytes\n"
        "\tTotal size:        %d bytes\n"
        "Sorted identifiers array:\n"
        "\tElements:          %d\n"
        "\tElems allocated:   %d\n"
        "\tTotal size:        %d bytes\n"
        "------------------------------------\n"
        ,
        id_arrs_count,
        id_arr_size,
        total_ids_size,

        lit_arrs_count,
        lit_arr_size,
        total_lits_size,

        sia->size,
        sia->allocated,
        total_sia_size
        );

    return total_ids_size + total_lits_size + total_sia_size;
}



GET_BLOCKS_COUNT_IMPL( atom_blocks_count, AtomBlock );

/*
 * dumps atoms memory state
 */
static size_t
dump_atoms_mem_state( AllocContext * c, FILE * fout )
{
    const AtomBlock *   b = c->impl->atoms.atom_block;
    const size_t        blk_count = atom_blocks_count( b );
    const size_t        blk_size = (c->settings.atom_chunks_grow_size - 1) * sizeof(char) +
        sizeof(AtomBlock);
    const size_t        total_blocks_size = blk_size * blk_count;

    fprintf(
        fout,
        "Atom allocator memory state:\n"
        "\tBlocks count:      %d\n"
        "\tBlock size:        %d bytes\n"
        "\tTotal blocks size: %d bytes\n"
        "------------------------------------\n"
        ,
        blk_count,
        blk_size,
        total_blocks_size
        );

    return total_blocks_size;
}

void
dump_mem_state( AllocContext * c, FILE * fout )
{
    size_t  list_mem_state;
    size_t  ids_mem_state;
    size_t  atoms_mem_state;
    size_t  mem_per_context_impl= sizeof(AllocContextImpl);

    fputs( "Context memory state:\n", fout );

    list_mem_state  = dump_list_mem_state( c, fout );
    ids_mem_state   = dump_ids_mem_state( c, fout );
    atoms_mem_state = dump_atoms_mem_state( c, fout );

    fprintf( fout,
        "Total:\n"
        "\tList allocators:   %d bytes\n"
        "\tIds allocators:    %d bytes\n"
        "\tInternal overhead: %d bytes\n"
        "\tTotal:             %d bytes\n"
        "------------------------------------\n"
        ,
        list_mem_state,
        ids_mem_state,
        mem_per_context_impl,
        list_mem_state + ids_mem_state + mem_per_context_impl
        );
}
